// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: qiangluo

#include "coin2/exchange/base/symbology/file_monitor.h"

#include <string.h>
#include <sys/stat.h>

#include "coin2/exchange/base/order/parser.h"

namespace coin2::exchange::base::symbology {

namespace {

int64_t GetFileLastChangeTime(const std::string& path) {
  struct stat st;
  memset(&st, 0x00, sizeof(struct stat));

  time_t last_time = 0;
  if (!stat(path.c_str(), &st)) {
    last_time = st.st_mtime;
  } else {
    PLOG(WARNING) << "stat error: ";
  }

  return static_cast<int64_t>(last_time) * 1'000'000'000LL;
}

}  // namespace

bool FileMonitor::AddFile(const std::string& path) {
  auto cur = monitor_file_map_.find(path);
  if (cur != monitor_file_map_.end()) {
    return true;
  }

  std::unique_ptr<record> ptr = std::make_unique<record>();
  ptr->path = path;
  ptr->last_check_time = GetCurrentTimestamp();
  ptr->last_change_time = GetFileLastChangeTime(path);
  ptr->is_updated = false;
  if (0 == ptr->last_change_time) {
    return false;
  }

  monitor_file_map_[path] = std::move(ptr);
  return true;
}

bool FileMonitor::HasFile(const std::string& path) {
  auto cur = monitor_file_map_.find(path);
  if (cur != monitor_file_map_.end()) {
    return true;
  }

  return false;
}

bool FileMonitor::IsFileUpdated(const std::string& path) {
  auto cur = monitor_file_map_.find(path);
  if (cur == monitor_file_map_.end()) {
    return false;
  }

  int64_t current_time = GetCurrentTimestamp();
  auto& ptr = monitor_file_map_[path];
  if (current_time - ptr->last_check_time > check_interval_) {
    int64_t mtime = GetFileLastChangeTime(path);
    if (mtime != ptr->last_change_time) {
      ptr->is_updated = true;
      return true;
    }
  } else {
    return ptr->is_updated;
  }

  return false;
}

void FileMonitor::RemoveFile(const std::string& path) {
  auto cur = monitor_file_map_.find(path);
  if (cur == monitor_file_map_.end()) {
    return;
  }

  monitor_file_map_.erase(cur);
}

bool FileMonitor::UpdateLastChangeTime(const std::string& path) {
  auto cur = monitor_file_map_.find(path);
  if (cur == monitor_file_map_.end()) {
    return false;
  }

  time_t mtime = GetFileLastChangeTime(path);
  if (0 == mtime) {
    return false;
  }

  cur->second->last_change_time = mtime;
  cur->second->is_updated = false;
  return true;
}

FileMonitor::FileMonitor(int64_t check_interval_second)
    : check_interval_(check_interval_second * 1'000'000'000LL) {}

}  // namespace coin2::exchange::base::symbology
